﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;

namespace Common
{
    public enum MessType
    {
        #region 文件传输消息头
        // 文件发送请求 (文件大小 文件名 等信息)
        //文件头
        FileHead = 128,
        //完成的文件
        FileCompleted,
        // 请求某个文件块
        FileSourceBlock,
        // 发送某个文件块
        FileTargetBlock,
        //请求终止
        FileSourceAbort,
        //发送终止
        FileTargetAbort,
        //请求暂停
        FileSourcePause,
        //发送暂停
        FileTargetPause,
        //请求继续
        FileSourceContinue,
        //发送暂停
        FileTargetContinue,
        #endregion

        //服务端分配客户端ID
        ClientID = 8,
        //客户端报告自己的信息
        ClientInfo,
        //心跳包(保持在线)
        Heart,
    }
    public class ClientTyep
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Prot { get; set; }

        const int IDIndex = 0;
        const int NameIndex = 4;
        const int ProtIndex = 8;

        public int StreamLength = 12;

        public byte[] ToStream()
        {
            int len = Name.Length;
            byte[] temp = new byte[12 + len];
            Array.Copy(BitConverter.GetBytes(ID), 0, temp, IDIndex, 4);
            Array.Copy(BitConverter.GetBytes(len), 0, temp, NameIndex, 4);
            Array.Copy(BitConverter.GetBytes(Prot), 0, temp, ProtIndex, 4);

            Array.Copy(Encoding.Default.GetBytes(Name), 0, temp, StreamLength, len);

            return temp;

        }

        public void Read(byte[] temp)
        {
            ID = BitConverter.ToInt32(temp, IDIndex);
            int len = BitConverter.ToInt32(temp, NameIndex);
            Prot = BitConverter.ToInt32(temp, ProtIndex);

            Name = Encoding.Default.GetString(temp, ProtIndex, len);
        }
    }
    public class StreamHead
    {
        // 这里控制着报头各数据的偏移地址
        // 用于将此类进行序列化和反序化
        const int lengthIndex = 0;
        const int IDIndex = 4;
        const int DataTypeIndex = 8;
        const int MessTypeIndex = 12;

        public int ID { get; set; }
        public MessType MessType { get; set; }
        public DataType DataTye { get; set; }

        public static int HeadLength = 16;

        public byte[] ToStream()
        {
            int length = HeadLength;

            byte[] stream = new byte[HeadLength];
            Array.Copy(BitConverter.GetBytes(length), 0, stream, lengthIndex, 4);
            Array.Copy(BitConverter.GetBytes(ID), 0, stream, IDIndex, 4);
            Array.Copy(BitConverter.GetBytes((int)DataTye), 0, stream, DataTypeIndex, 4);
            Array.Copy(BitConverter.GetBytes((int)MessType), 0, stream, MessTypeIndex, 4);

            return stream;
        }

        public static void Write(byte[] stream, int id, DataType type, MessType mess, int length)
        {
            Array.Copy(BitConverter.GetBytes(length), 0, stream, lengthIndex, 4);
            Array.Copy(BitConverter.GetBytes(id), 0, stream, IDIndex, 4);
            Array.Copy(BitConverter.GetBytes((int)type), 0, stream, DataTypeIndex, 4);
            Array.Copy(BitConverter.GetBytes((int)mess), 0, stream, MessTypeIndex, 4);
        }

        public static void Read(byte[] stream, out int length, out int clientID, out DataType dataType, out MessType messType)
        {
            length = BitConverter.ToInt32(stream, lengthIndex);
            clientID = BitConverter.ToInt32(stream, IDIndex);
            dataType = (DataType)BitConverter.ToInt32(stream, DataTypeIndex);
            messType = (MessType)BitConverter.ToInt32(stream, MessTypeIndex);
        }
    }

    public class SocketClient
    {
        public int ID;
        public Socket Client;
        public Thread Receiver;
        public Thread Sender;
        public List<byte[]> Message;//待发送消息
        public string IP;
        public DateTime LastTime;
        public ClientTyep Type;
    }

    public enum DataType
    {
        // 传输的数据类型
        Base = 0,
        File = 64,
        Task,
    }

    public enum FileState
    {
        None = 0,
        //传输中
        Transing,
        //暂停
        Paused,
        //终止
        Aborted,
        //完整
        Completed,
    }

    public enum FileList
    {
        None,
        Source,
        Target,
    }

    public class StreamFile
    {
        public FileState State;
        public int ID;
        public int FileID;
        public long Size;
        public long Seek;
        public string FileName;
        public string MD5;
        public string Path;


        const int IDIndex = 0;
        const int StateIndex = 4;
        const int FileIDIndex = 8;
        const int SizeIndex = 12;
        const int SeekIndex = 20;
        const int FileNameIndex = 28;
        const int MD5Index = 32;
        const int PathIndex = 36;

        public int HeadLength = 40;
        // 每个文件块的大小 (网速慢应减小块大小)
        public const int BlockMaxSize = 40 * 1024;
        //最大请求发送文件块次数
        public const int MaxConcurrentSum = 40;

        public byte[] ToStream()
        {
            byte[] nameStream = Encoding.Default.GetBytes(FileName);
            int length = nameStream.Length;
            byte[] md5Stream = Encoding.Default.GetBytes(MD5);
            length += md5Stream.Length;
            byte[] pathStream = Encoding.Default.GetBytes(Path);
            length += pathStream.Length;

            byte[] stream = new byte[HeadLength + length];
            Array.Copy(BitConverter.GetBytes(ID), 0, stream, IDIndex, 4);
            Array.Copy(BitConverter.GetBytes((int)State), 0, stream, StateIndex, 4);
            Array.Copy(BitConverter.GetBytes(FileID), 0, stream, FileIDIndex, 4);
            Array.Copy(BitConverter.GetBytes(Size), 0, stream, SizeIndex, 8);
            Array.Copy(BitConverter.GetBytes(Seek), 0, stream, SeekIndex, 8);
            Array.Copy(BitConverter.GetBytes(nameStream.Length), 0, stream, FileNameIndex, 4);
            Array.Copy(BitConverter.GetBytes(md5Stream.Length), 0, stream, MD5Index, 4);
            Array.Copy(BitConverter.GetBytes(pathStream.Length), 0, stream, PathIndex, 4);

            Array.Copy(nameStream, 0, stream, HeadLength, nameStream.Length);
            Array.Copy(md5Stream, 0, stream, HeadLength + nameStream.Length, md5Stream.Length);
            Array.Copy(pathStream, 0, stream, HeadLength + nameStream.Length + md5Stream.Length, pathStream.Length);

            return stream;

        }

        public void Read(byte[] stream)
        {
            ID = BitConverter.ToInt32(stream, IDIndex);
            State = (FileState)BitConverter.ToInt32(stream, StateIndex);
            FileID = BitConverter.ToInt32(stream, FileIDIndex);
            Size = BitConverter.ToInt64(stream, SizeIndex);
            Seek = BitConverter.ToInt64(stream, SeekIndex);
            int nameLength = BitConverter.ToInt32(stream, FileNameIndex);
            int md5Length = BitConverter.ToInt32(stream, MD5Index);
            int pathLength = BitConverter.ToInt32(stream, PathIndex);

            FileName = Encoding.Default.GetString(stream, HeadLength, nameLength);
            MD5 = Encoding.Default.GetString(stream, HeadLength + nameLength, md5Length);
            Path = Encoding.Default.GetString(stream, HeadLength + nameLength + md5Length, pathLength);
        }
    }

    public class SenderFile
    {
        public int ID { get; set; }
        public int FileID { get; set; }
        public string FilePath { get; set; }
        public long Seek { get; set; }
        public long Size { get; set; }
        public FileState State { get; set; }

        //const int IDIndex = 0;
        //const int FileIDIndex = 4;
        //const int FilePathIndex = 8;
        //const int SeekIndex = 12;
        //const int SizeIndex = 20;
        //const int StateIndex = 28;

        //public int StreamLength = 32;

        //public byte[] ToStream()
        //{
        //    int len = FilePath.Length;
        //    byte[] temp = new byte[StreamLength + len];

        //    Array.Copy(BitConverter.GetBytes(ID), 0, temp, IDIndex, 4);
        //    Array.Copy(BitConverter.GetBytes(FileID), 0, temp, FileIDIndex, 4);
        //    Array.Copy(BitConverter.GetBytes(len), 0, temp, FilePathIndex, 4);
        //    Array.Copy(BitConverter.GetBytes(Seek), 0, temp, SeekIndex, 8);
        //    Array.Copy(BitConverter.GetBytes(Size), 0, temp, SizeIndex, 8);
        //    Array.Copy(BitConverter.GetBytes((int)State), 0, temp, StateIndex, 4);

        //    Array.Copy(Encoding.Default.GetBytes(FilePath), 0, temp, StreamLength, len);

        //    return temp;
        //}

        //public void Read(byte[] stream)
        //{
        //    ID = BitConverter.ToInt32(stream, IDIndex);
        //    FileID = BitConverter.ToInt32(stream, FileIDIndex);
        //    Seek = BitConverter.ToInt64(stream, SeekIndex);
        //    Size = BitConverter.ToInt64(stream, SizeIndex);
        //    State = (FileState)BitConverter.ToInt32(stream, StateIndex);
        //    int len = BitConverter.ToInt32(stream, FilePathIndex);

        //    FilePath = BitConverter.ToString(stream, StreamLength, len);
        //}
    }

    public class DataDisp : EventArgs
    {
        public byte[] Stream;
        public int ID;
        public DataType Data;
        public MessType Type;
    }

    public class SendMessage : EventArgs
    {
        public int ID;
        public byte[] Stream;
    }
}
